from datetime import datetime
from decimal import Decimal

from django.db.models import Sum, F
from django.utils import timezone
from rest_framework.generics import get_object_or_404

from apps.booking.models import Booking, BookingPrice
from apps.location.models import RoomPrice, LocationTierSetting, Room, Location

# from decimal import Decimal
from apps.core.utils import date_time as datetime_helper


def get_tiers(location, start_datetime, duration_current_booking, adjust_time=0):
    start_of_month = datetime_helper.start_of_month(start_datetime)
    end_of_month = datetime_helper.end_of_month(start_datetime)
    bookings = Booking.objects.filter(
        start_date__range=[start_of_month, end_of_month],
        room__isnull=False
    )

    bookings = bookings.annotate(
        duration=(F('end_time') - F('start_time')))

    duration = bookings.aggregate(Sum('duration')).get('duration__sum')
    week_hours = (duration.total_seconds() - adjust_time) / 3600 if \
        duration is not None else 0

    current_hours = duration_current_booking / 3600
    total_hours_booking = week_hours + current_hours

    tiers = LocationTierSetting.objects.filter(location=location)
    tiers_list = list(tiers.values_list('end_hours', flat=True))
    tiers_name = list(tiers.values_list('tier', flat=True))
    tiers_ids = list(tiers.values_list('id', flat=True))
    temp = len(tiers_list)
    tiers_list.insert(0, 0)

    tiers_name.insert(len(tiers), 'Tier 0')
    tiers_ids.insert(len(tiers), 0)

    list_block_hours = []

    for i in range(len(tiers_list) - 1, -1, -1):
        if total_hours_booking > int(tiers_list[i]) \
                and total_hours_booking >= week_hours:
            if week_hours > int(tiers_list[i]):
                hours = total_hours_booking - week_hours
            else:
                hours = total_hours_booking - int(tiers_list[i])
            if hours <= 0:
                break
            if i >= (len(tiers_list) - 1):
                total_hours_booking = total_hours_booking - hours
                list_block_hours.append({
                    'tier': tiers_name[temp - 1],
                    'id': tiers_ids[temp - 1],
                    'hours': hours
                })
            elif i == 0:
                total_hours_booking = total_hours_booking - hours
                list_block_hours.append({
                    'tier': tiers_name[i],
                    'id': tiers_ids[i],
                    'hours': hours
                })
            else:
                total_hours_booking = total_hours_booking - hours
                list_block_hours.append({
                    'tier': tiers_name[temp],
                    'id': tiers_ids[temp],
                    'hours': hours
                })

        temp = temp - 1

    return list_block_hours


def create_booking(validated_data):
    room_id = validated_data['room']
    room = get_object_or_404(Room, id=room_id)

    validated_data['room'] = room

    if 'location' in validated_data:
        location = Location.objects.filter(id=validated_data.get('location'))
        validated_data['location'] = location
    else:
        validated_data['location'] = room.location

    location = validated_data.get('location')

    provider = validated_data.get('provider')

    date = validated_data.get('start_date')
    end_time = validated_data.get('end_time')
    start_time = validated_data.get('start_time')

    start_datetime = timezone.make_aware(
        (datetime.combine(date.date(), datetime.strptime(start_time, "%H:%M:%S").time())),
        timezone.get_current_timezone())
    end_datetime = timezone.make_aware((datetime.combine(date.date(), datetime.strptime(end_time, "%H:%M:%S").time())),
                                       timezone.get_current_timezone())

    duration = (end_datetime - start_datetime).total_seconds()

    tiers = get_tiers(location, date, duration)
    if room.tiers_excluded is False:
        room_prices = None
        total_price = Decimal(0.0)
        if room is not None:
            room_prices = list(RoomPrice.objects.filter(
                room=room.id))
            for room_price in room_prices:
                for tier in tiers:
                    if room_price.tier.tier == tier.get('tier'):
                        total_price += room_price.cost * \
                                       Decimal(tier.get('hours'))
        validated_data['room_cost'] = total_price
        data = validated_data
        data.pop('location')
        data.pop('room')
        data['room'] = room.id
        booking = Booking.objects.create(**data)
        if room_prices is not None:
            for room_price in room_prices:
                for tier in tiers:

                    if room_price.tier.tier == tier.get('tier'):
                        BookingPrice.objects.create(
                            booking=booking,
                            tier=tier['tier'],
                            hours=tier['hours'],
                            price=room_price.cost)

    else:
        validated_data['room_cost'] = Decimal(0.0)
        data = validated_data
        data.pop('location')
        room = data.pop('room')
        booking = Booking.objects.create(**data)
        hours = 0
        for tier in tiers:
            hours = hours + tier['hours']
        BookingPrice.objects.create(
            booking=booking,
            hours=hours,
            price=Decimal(0.0))

    return booking, room
